iT邦幫忙

2023 iThome 鐵人賽

DAY 5
0
Modern Web

Phoenix 1.7 完全教學系列 第 5

5 快速上手夠用的 Elixir (條件判斷)

  • 分享至 

  • xImage
  •  

在上一篇我們有使用同名函式與 pattern matching 做出函式層級的條件判斷,
當然 Elixir 也是有 ifelse 的。

if 函式

if 3 > 2 do
  "三大於二"
end


list = [1, 2]
if Enum.any?(list) do
  "list 裡面有東西"
end

我們也可以加上 else

your_lucky_number = 5
if Enum.member?([1, 2, 3], your_lucky_number) do
  "中獎"
else
  "沒中獎"
end

要注意的是 Elixir 沒有 else if,如果是多項條件的話可以用待會介紹的 casecond

為什麼說是 if 函式 而不是 語法呢?
原來 if/2 是在 Kernel 底下的函式 Kernel.if/2
(註:if 使用了 macro 讓我們用起來能有像其他語言的語法)

因為他是其實是函式,所以我們可以這樣使用

if(3 > 2, do: "三大於二啦")

if(false, do: "真", else: "假")

if/2 就如上面寫的,收兩個變數,第一個是我們要判斷的條件,上面的範例為 false ,接著看起來有 doelse 兩個但是其實是一個我們在第二篇提到的 keyword list ,如果 keyword list 是最後一個變數的話,可以省略 []

# 加上以省略的 []
if(false, [do: "真", else: "假"])

# 不用 keyword list 的簡寫
if(false, [{:do, "真"}, {:else, "假"}])

所以通常會怎麼使用呢?

如果判斷與結果情況複雜的時候會寫成多行

if Map.has_key?(%{a: 1}, :a) do
  # 很多判斷
  # 更多行
  "Map 裡面有 :a"
else
  nil
end

如果判斷與結果情況簡單的時候會寫成一行

if Map.has_key?(%{a: 1}, :a), do: 1, else: 2

另外常常會有用變數收集 if 結果的情形

message =
  if Enum.any?([]) do
    "空的"
  else
    "有東西"
  end
message
#=> "空的"

cond

剛剛才講說沒有 else if,那要怎麼做多項條件的判斷呢? 這時候就可以用 cond ,他會從上到下判斷,直到找到第一個條件為真,並執行 -> 後面的程式區塊

i = 2
cond do
  i < 1 -> "小於一"
  Integer.is_odd(i) -> "是奇數"
  is_atom(i) -> "是 atom"
  true -> "其他"
end
#=> "其他"

在上面這個例子,我們一個一個把 i 帶進去 -> 左邊的判斷,第一個變成正向的時候就會執行 -> 右邊的程式區塊

(在 Elixir 裡,if 與 cond 判斷時,只有 false 與 nil 是反向,其他不管是 true, 數值, 空 list, 都是正向)

另外,如果沒有任何一個條件為成立的話,會跳出 CondClauseError 錯誤,如果要這不是預期行為的話,可以在最後加上 true -> 來當作預設值,這樣就算前面全部都失敗,這一個一定會成立。

case

case 使用了 pattern matching 來做判斷,是非常方便的語法

case %{name: "Jack", age: 18} do
  %{name: "PB"} -> "You are PB!, 99% off!"
  %{level: level} -> "#{level * 10}% off!"
  _ -> "Error"
end

這邊是上一篇練習的 case 版本,同樣的,如果有要處理上面條件都沒有匹配(matching)到的預設值的話,可以在最後一行處理,只是這邊跟剛剛的 cond 不同,是使用 _ 來讓他一定匹配成功,如果有需要左邊的值的話,可以使用變數匹配取出。

Guard (when 語法)

我們也可以替 pattern matching 的匹配判斷加上額外的要求,
我們沿用上面的折扣例子,

  case %{name: "Jack", age: 18} do
  %{name: "PB"} ->
    "You are PB!, 99% off!"

  %{level: level} when level > 0 && level <= 10 ->
    "#{level * 10}% off!"

  _ ->
    "Error"
end

我們在匹配 level 那行增加了額外的條件,level 必須大於 0 且小於等於 10

這個行為在函式呼叫也可以使用

def take_file(i) when is_integer(i) do
  "i 一定是 Integer 才會進入這個匹配結果"
end
def take_file(i) do
  "別的結果"
end

上一篇
4 快速上手夠用的 Elixir (Pattern matching)
下一篇
6 快速上手夠用的 Elixir (常用慣例與寫法)
系列文
Phoenix 1.7 完全教學30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言